package primetest.impl.controler;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.inject.Named;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import primetest.dto.BedDto;
import primetest.dto.BuildingDto;
import primetest.dto.ConfigDto;
import primetest.dto.CreateWardWizardDto;
import primetest.dto.CreateWardWizardDto.CheckCondition;
import primetest.dto.DepartmentDto;
import primetest.dto.WardDto;
import primetest.faces.WardListModel;
import primetest.impl.manager.SessionManager;
import primetest.impl.service.BuildingService;
import primetest.impl.service.ConfigService;
import primetest.impl.service.DepartmentService;
import primetest.impl.service.WardService;

@Named("wardListControler")
@SessionScoped
public class WardListControler implements Serializable {

	/**
	 *
	 */
	private static final long serialVersionUID = -2341239310873546662L;

	private Logger logger = LoggerFactory.getLogger(this.getClass());

	@Inject
	private SessionManager sessionManager;

	private WardListModel wardList = null;
	private List<WardDto> baseWardList;
	private WardDto selectedWard = new WardDto();
	private WardDto backWard = new WardDto();

	private CreateWardWizardDto createWardWizard;

	public static String WARD_CONDITION = "WardConditions";

	private int first;
	private boolean editMode = false;
	private boolean addMode = false;
	private boolean editConditionMode = false;

	private List<CheckCondition> conditionList;
	private String configStr = "";

	private List<WardDto> filteredTerms;

	public boolean getEditMode() {
		return editMode;
	}

	public boolean getAddMode() {
		return addMode;
	}

	@Inject
	private WardService wardService;

	@Inject
	private ConfigService configService;

	@Inject
	private BuildingService buildingService;

	@Inject
	private DepartmentService departmentService;

	@Inject
	private BedListControler bedListControler;

	public WardListModel getWardList() {
		if (baseWardList == null) {
			try {
				baseWardList = wardService.getWardList();
				Collections.sort(baseWardList, new Comparator<WardDto>() {
					@Override
					public int compare(WardDto a, WardDto b) {
						return a.getName().compareToIgnoreCase(b.getName());
					}
				});
				wardList = new WardListModel(baseWardList);
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}

		return baseWardList == null ? new WardListModel(
				new ArrayList<WardDto>()) : wardList;
	}

	public List<WardDto> getBaseWardList() {
		if (baseWardList == null) {
			try {
				baseWardList = wardService.getWardList();
				Collections.sort(baseWardList, new Comparator<WardDto>() {
					@Override
					public int compare(WardDto a, WardDto b) {
						return a.getName().compareToIgnoreCase(b.getName());
					}
				});
				wardList = new WardListModel(baseWardList);
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}

		return baseWardList;
	}

	public void deleteWard() throws IOException {
		wardService.deleteWard(selectedWard.getKey());
		baseWardList.remove(selectedWard);
		for (BedDto bedDto : selectedWard.getBedDtos()) {
			bedListControler.getBaseBedList().remove(bedDto);
		}
	}

	public void reload() {
		baseWardList = null;
	}

	public WardDto getSelectedWard() {
		return selectedWard;
	}

	public void setSelectedWard(WardDto selectedWard) {
		this.selectedWard = selectedWard;
	}

	public int getFirst() {
		return first;
	}

	public void setFirst(int first) {
		this.first = first;
	}

	public void startEditWard() {
		editMode = true;
		backWard.setAll(selectedWard);
	}

	public void saveEditWard() {
		try {
			if (selectedWard.isValid()) {
				wardService.updateWard(selectedWard);
				editMode = false;
			} else {
				sessionManager.addGlobalMessageFatal("Ward invalid", null);
			}

		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void cancelEditWard() {
		editMode = false;
		selectedWard.setAll(backWard);
	}

	public void startAddWard() throws IOException {
		addMode = true;
		createWardWizard = new CreateWardWizardDto(getWardConfigStr());
	}

	public void addNewWard() throws IOException {
		if (createWardWizard.isValid()) {
			BuildingDto buildingDto = buildingService
					.findBuilding(createWardWizard.getBuildingKey());
			DepartmentDto departmentDto = departmentService
					.getDepartment(createWardWizard.getDepartmentSeq());
			String wardPrefix = createWardWizard.getWardPrefix();
			String bedPrefix = createWardWizard.getBedPrefix();
			int bedCount = createWardWizard.getBedCount();
			int startIndex = createWardWizard.getWardStartIndex();
			for (int i = 0; i < createWardWizard.getWardCount(); i++) {
				WardDto warDto = new WardDto();
				warDto.setBuildingDto(buildingDto);
				warDto.setFloor(createWardWizard.getFloor());
				warDto.setName(wardPrefix
						+ new Integer(i + startIndex).toString());
				warDto.setDepartmentDto(departmentDto);
				warDto.setExtraInfo(createWardWizard.getExtraInfo());
				List<BedDto> beds = new ArrayList<BedDto>();
				for (int j = 0; j < bedCount; j++) {
					beds.add(new BedDto());
					beds.get(j).setName(warDto.getName() + bedPrefix + j);
					beds.get(j).setWardKey(warDto.getKey());
					beds.get(j).setWardDto(warDto);
					bedListControler.getBaseBedList().add(beds.get(j));
				}
				warDto.setBedDtos(beds);
				warDto.setConditions(createWardWizard.getBooleanConditions());
				wardService.addWard(warDto);
				baseWardList.add(warDto);
			}
			addMode = false;
		} else {
			sessionManager.addGlobalMessageFatal("Ward Wizard invalid", null);
		}
	}

	public void cancelAddWard() {
		addMode = false;
	}

	public List<WardDto> getFilteredTerms() {
		return filteredTerms;
	}

	public void setFilteredTerms(List<WardDto> filteredTerms) {
		this.filteredTerms = filteredTerms;
	}

	public CreateWardWizardDto getCreateWardWizard() {
		if (createWardWizard == null) {
			createWardWizard = new CreateWardWizardDto(getWardConfigStr());
		}
		return createWardWizard;
	}

	public void setCreateWardWizard(CreateWardWizardDto createWardWizard) {
		this.createWardWizard = createWardWizard;
	}

	public String getWardConfigStr() {
		try {
			return configService.findConfig(WARD_CONDITION).getValue();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return "";
	}

	private CheckCondition selectedCondition;
	private CheckCondition newCondition;

	public boolean isEditConditionMode() {
		return editConditionMode;
	}

	public void setEditConditionMode(boolean editConditionMode) {
		this.editConditionMode = editConditionMode;
	}

	public List<CheckCondition> getConditionList() {
		String str = getWardConfigStr();
		if (conditionList == null || !str.equals(configStr)) {
			configStr = str;
			conditionList = new ArrayList<CheckCondition>();
			for (String config : configStr.split("/")) {
				if (!config.equals("")) {
					String[] strs = config.split(":");
					CheckCondition con = new CheckCondition();
					con.setTerm(strs[0]);
					con.setRendered(strs[1].equals("1"));
					con.setCondition(false);
					if (con.isRendered()) {
						conditionList.add(con);
					}
				}
			}
		}
		return conditionList;
	}

	public void setConditionList(List<CheckCondition> conditionList) {
		this.conditionList = conditionList;
	}

	public void startEditCondition() {
		editConditionMode = true;
		newCondition = new CheckCondition();
		newCondition.setRendered(true);
	}

	public void deleteCondition() {
		selectedCondition.setRendered(false);
		conditionList.remove(selectedCondition);
	}

	public void addCondition() {
		if (newCondition.getTerm().equals("")) {
			sessionManager.addGlobalMessageFatal(
					"Term cannot not be empty", null);
			return;
		}
		if (newCondition.getTerm().contains("/") || newCondition.getTerm().contains(":")) {
			sessionManager.addGlobalMessageFatal(
					"Term contains invalid character like / :", null);
			return;
		}
		for (CheckCondition con : conditionList) {
			if (con.getTerm().equals(newCondition.getTerm())) {
				sessionManager.addGlobalMessageFatal(
						"Condition same with current condition", null);
				return;
			}
		}
		conditionList.add(newCondition);
		newCondition = new CheckCondition();
		newCondition.setRendered(true);
	}

	public void saveEditCondition() throws IOException {
		StringBuilder sb = new StringBuilder();
		for (String config : configStr.split("/")) {
			if (!config.equals("")) {
				String[] strs = config.split(":");

				boolean rendered = false;
				for (CheckCondition con : conditionList) {
					if (con.getTerm().equals(strs[0])) {
						rendered = true;
						conditionList.remove(con);
						break;
					}
				}
				if (sb.length() != 0) {
					sb.append("/");
				}
				sb.append(strs[0]);
				if (rendered) {
					sb.append(":1");
				} else {
					sb.append(":0");
				}
			}
		}
		for (CheckCondition con : conditionList) {
			if (sb.length() != 0) {
				sb.append("/");
			}
			sb.append(con.getTerm());
			sb.append(":1");
		}
		String str = sb.toString();
		if (!str.equals(configStr)) {
			ConfigDto configDto = new ConfigDto();
			configDto.setKey(WARD_CONDITION);
			configDto.setValue(str);
			configService.updateConfig(configDto);
		}
		editConditionMode = false;
		conditionList = null;
	}

	public void cancelEditCondition() {
		editConditionMode = false;
		conditionList = null;
	}

	public CheckCondition getSelectedCondition() {
		return selectedCondition;
	}

	public void setSelectedCondition(CheckCondition selectedCondition) {
		this.selectedCondition = selectedCondition;
	}

	public CheckCondition getNewCondition() {
		return newCondition;
	}

	public void setNewCondition(CheckCondition newCondition) {
		this.newCondition = newCondition;
	}
}
